﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using umbraco.DataServices.Linq.Schema;

namespace umbraco.DataServices.Linq
{
    public class UmbracoContext : IDisposable {

        private XDocument _xml;
        private readonly ISchema _schemaToUse;

        public UmbracoContext(XDocument xml, Dictionary<PropertyIdentifier, Type> registeredTypes, IDocumentTypeSignatureCollection signatureCollection, ISchema schema) {
            if (xml == null)
                throw new ArgumentNullException("xml");
            if (registeredTypes == null)
                throw new ArgumentNullException("registeredTypes");
            if (signatureCollection == null)
                throw new ArgumentNullException("signatureCollection");
            _xml = xml;
            RegisteredPropertyTypes = registeredTypes;
            SignatureCollection = signatureCollection;
            _schemaToUse = schema;
        }

        public Dictionary<PropertyIdentifier, Type> RegisteredPropertyTypes { get; private set; }

        public IDocumentTypeSignatureCollection SignatureCollection { get; private set; }

        public XDocument Xml {
            get { return _xml; }
        }

        public ISchema Schema {
            get { return _schemaToUse; }
        }

        public IEnumerable<UmbracoNode> Select(IEnumerable<string> docAlias) {
            var documentTypes = GetDescendantDocumentTypes(docAlias);
            var rootDocument = Xml.Root;
            return new NodeIterator(this, Schema.GetDescendantsNamed(rootDocument, documentTypes), docAlias);
        }

        public IEnumerable<UmbracoNode> Select(string docAlias) {
            var documentTypes = GetDescendantDocumentTypes(docAlias);
            var rootDocument = Xml.Root;
            return new NodeIterator(this, Schema.GetDescendantsNamed(rootDocument, documentTypes), docAlias);
        }

        public IEnumerable<UmbracoNode> Select() {
            var rootDocument = Xml.Root;
            return new NodeIterator(this, Schema.GetDescendants(rootDocument), string.Empty);
        }

        public IEnumerable<UmbracoNode> SelectRoot() {
            var rootDocument = Xml.Root;
            return new NodeIterator(this, Schema.GetChildren(rootDocument), string.Empty);
        }

        public void Dispose() {
            _xml = null;
        }

        public IEnumerable<string> GetDescendantDocumentTypes(IEnumerable<string> aliases) {
            var allItems = aliases.SelectMany(p => SignatureCollection.GetDescendantDocumentTypes(p));
            return allItems.Select(p => p.Alias).Union(aliases);
        }

        public IEnumerable<string> GetDescendantDocumentTypes(string aliases) {
            return GetDescendantDocumentTypes(new[] {aliases});
        }
    }
}
